Passed
Push — develop ( 0b98e4...d22535 )
by Endre
05:35
created

ServiceWorkerManager.clearOldCaches   A

Complexity

Conditions 2

Size

Total Lines 9
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 9
dl 0
loc 9
ccs 4
cts 4
cp 1
crap 2
rs 9.95
c 0
b 0
f 0
1
export interface ServiceWorkerEventMap {
2
  'activate': ExtendableEvent;
3
  'fetch': FetchEvent;
4
  'install': InstallEvent;
5
  'waiting': ExtendableEvent;
6
}
7
8
export interface ServiceWorkerGlobalScope {
9
  readonly caches: CacheStorage;
10
  addEventListener<K extends keyof ServiceWorkerEventMap>(
11
    type: K,
12
    listener: (event: ServiceWorkerEventMap[K]) => any,
13
    useCapture?: boolean
14
  ): void;
15
  skipWaiting(): void;
16
}
17
18
export interface InstallEvent extends ExtendableEvent {
19
  readonly activeWorker: ServiceWorker;
20
}
21
22
export interface ExtendableEvent extends Event {
23
  waitUntil(promise: Promise<any>): void;
24
}
25
26
export interface FetchEvent extends Event {
27
  readonly isReload: boolean;
28
  readonly request: Request;
29
  readonly clientId: string;
30
  respondWith(all: any): Response;
31
}
32
33
// https://developers.google.com/web/fundamentals/primers/service-workers
34
export class ServiceWorkerManager {
35
  worker: ServiceWorkerGlobalScope;
36
  caches: CacheStorage;
37
  version: string;
38
  fileList: string[];
39
40
  constructor(worker: any, caches: CacheStorage, version: string, fileList: string[]) {
41 8
    this.worker = worker;
42 8
    this.caches = caches;
43 8
    this.version = version;
44 8
    this.fileList = fileList;
45
46 8
    this.worker.addEventListener('install', this.installCache.bind(this));
47 8
    this.worker.addEventListener('activate', this.activateCache.bind(this));
48 8
    this.worker.addEventListener('fetch', this.fetchRequest.bind(this));
49
  }
50
51
  installCache(event: InstallEvent) {
52 1
    this.worker.skipWaiting(); // No wait, content immediately active (even partially)
53 1
    event.waitUntil(this.cacheFiles());
54
  }
55
56
  activateCache(event: ExtendableEvent) {
57 1
    event.waitUntil(this.clearOldCaches());
58
  }
59
60
  fetchRequest(event: FetchEvent) {
61 5
    event.respondWith(this.fetch(event.request));
62
  }
63
64
  async cacheFiles() {
65 1
    const cache: Cache = await this.caches.open(this.version);
66 1
    return cache.addAll(this.fileList);
67
  }
68
69
  async clearOldCaches() {
70 1
    const cacheNames = await this.caches.keys();
71
72 1
    return Promise.all(
73
      cacheNames.map(
74
        (cacheName: string) => {
75 2
          if (cacheName != this.version) {
76 1
            return this.caches.delete(cacheName);
77
          }
78
        }
79
      )
80
    );
81
  }
82
83
  async fetch(request: Request) {
84 5
    const response: Response | undefined = await this.caches.match(request);
85
86 5
    if (response) {
87 1
      return response;
88
    }
89
90 4
    const fetchResponse: Response = await fetch(request);
91 5
    if (!fetchResponse || fetchResponse.status !== 200 || fetchResponse.type !== 'basic') {
92 3
      return fetchResponse;
93
    }
94
95
    // IMPORTANT: Clone the response. A response is a stream
96
    // and because we want the browser to consume the response
97
    // as well as the cache consuming the response, we need
98
    // to clone it so we have two streams.
99 1
    const responseToCache: Response = fetchResponse.clone();
100
101 1
    const cache: Cache = await this.caches.open(this.version);
102 1
    await cache.put(request, responseToCache);
103
104 1
    return fetchResponse;
105
  }
106
}
107
108 1
const version: string = 'VERSION'; // Will be generated by script
109 1
const fileList: string[] = []; // Will be generated by script
110 2
if (this) {
111
  new ServiceWorkerManager(this, caches, version, fileList);
112
}
113